package testoo;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.apache.log4j.FileAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;

import testooj3.compatibility.InterfacesCompatibilityChecker;


public class DatasetLoader implements Serializable {
		/**
		 * 
		 */
		private static final long serialVersionUID = -163857493039425244L;
		protected ExecutorService executor = Executors.newFixedThreadPool(1);
		protected static final String LOADER_LOG = "DatasetLoader";
		protected static final String DATASET_PROPERTIES_FILE = "datasetProperties.xml";
		protected static final String LOADER_LOGFILE = "./loaderLog.txt";
		protected static final FileAppender fileAppender = new FileAppender();
		protected File[] skeletonFiles;


		public static void main(String[] args) {
				setupLoggers();
				DatasetLoader loader = new DatasetLoader();
				loader.run();
		}
		
		private static void setupLoggers() {
			try {
				fileAppender.setWriter(new BufferedWriter(new FileWriter(new File(LOADER_LOGFILE))));
			} catch (IOException e) {
				e.printStackTrace();
			}
			fileAppender.setLayout(new PatternLayout());
			Logger.getLogger(LOADER_LOG).addAppender(fileAppender);
		}
		
		public void run() {
			FileInputStream datasetPropertiesInStream;
			final DataSetProperties datasetProperties = new DataSetProperties();
			StringBuffer similarityBuffer = new StringBuffer();
			try {
				datasetPropertiesInStream = new FileInputStream(new File(DATASET_PROPERTIES_FILE));
				datasetProperties.loadProperties(datasetPropertiesInStream);
				File inputDir = new File(datasetProperties.getProperty(DataSetProperty.INPUT_PATH));
				if (inputDir.list() == null) {
					  System.out.println("No files into the specified folder");
				}
				else {
					LinkedList<Future<String>> futures = new LinkedList<Future<String>>();
					System.out.println("Analyzing Folder: ");
					skeletonFiles = new File(datasetProperties.getProperty(DataSetProperty.QUERY_PATH) + File.separator + "test").listFiles();
					for (final File inputFile : inputDir.listFiles()) {
						if (inputFile.toString().endsWith(".txt")){													
							futures.add(
							executor.submit(new Callable<String>() {
								/**
								 * 
								 */
								@Override
								public String call() throws Exception {
									return executeInterfaceCompatibility(new File(datasetProperties.getProperty(DataSetProperty.RESOURCES_PATH)),
											new File(datasetProperties.getProperty(DataSetProperty.QUERY_PATH)), inputFile.toString());
								}
							}));
							}
					}
					for (Future<String> future : futures) {
						try {
							similarityBuffer.append(future.get());
						} catch (InterruptedException e) {
							e.printStackTrace();
						} catch (ExecutionException e) {
							e.printStackTrace();
						}
					}
				}
			} catch (FileNotFoundException e) {
				Logger.getLogger(LOADER_LOG).fatal("Dataset Loader Error - missing datasetProperties.xml");
			} 
			executor.shutdown();
			System.out.println("Writing Files...");
			FileWriter similarityResultsFile;
			try {
				similarityResultsFile = new FileWriter(new File(datasetProperties.getProperty(DataSetProperty.RESULTS_FILENAME)));
				BufferedWriter similarityResultsBuffer = new BufferedWriter(similarityResultsFile);
				similarityResultsBuffer.write(similarityBuffer.toString());
				similarityResultsBuffer.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			System.out.println("Done!");
		}

		private String executeInterfaceCompatibility(File resourcesPath, File queryPath, String originalQuery) {
			StringBuffer similarityBuffer = new StringBuffer();
			System.out.println("Executing IC for query: " + originalQuery);
			String originalQueryName = originalQuery.substring(originalQuery.lastIndexOf(File.separator)+1,originalQuery.lastIndexOf("."));
			similarityBuffer.append(originalQueryName + ",");
			System.out.println("\t QueryName: " + originalQueryName);
			try {
			    BufferedReader br = new BufferedReader(new FileReader(originalQuery));
			    String line = br.readLine();
			    while (line != null) {
			    	if (!line.isEmpty()){
		    			String wsdlName = line.split(",")[0];
		    			
			    		String originalClassName  = "query." + Character.toUpperCase(originalQueryName.charAt(0)) + originalQueryName.substring(1);
	    				String candidateClassName = "test." + wsdlName.replace(".wsdl", "");
	    				System.out.println("Original Class: " + originalClassName);
	    				System.out.println("Candidate Class: " + candidateClassName);
	    				double maxSimilarity = calculateCompatibility(queryPath, resourcesPath, originalClassName, candidateClassName);
						similarityBuffer.append(maxSimilarity + ",");
			    	}
			    	line = br.readLine();
			    }
	    		similarityBuffer.append(originalQueryName + System.lineSeparator());
			    br.close();
			}
			catch (Exception e){
				e.printStackTrace();
			}
			return similarityBuffer.toString();
		}
		
		private double calculateCompatibility(File queryPath, File resourcesPath, String originalClassName, String candidateClassName) {
			InterfacesCompatibilityChecker ict;
			Double comparationResult = 0.0;
			try {
				for (File skeletonFile : skeletonFiles) {
					String candidateSkeletonClass = candidateClassName + "Skeleton";
					if (skeletonFile.getName().replace(".class", "").equalsIgnoreCase(candidateSkeletonClass.replace("test.", ""))) {
						System.out.println("SkeletonFile: " + skeletonFile.getName());
						System.out.println("SkeletonCandidate: " + candidateSkeletonClass);
						ict = new InterfacesCompatibilityChecker(originalClassName, "test." + skeletonFile.getName().replace(".class", ""), false, queryPath.toString(), queryPath.toString());
						ict.run();
						comparationResult = ict.getMaxCompatibility(); 						
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			return comparationResult;
		}
}

